package com.jumi.microservice.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Set;

@Configuration
public class WebConfig {

	@Autowired
	private Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder;
	@Bean
	public MappingJackson2HttpMessageConverter MappingJsonpHttpMessageConverter() {

		ObjectMapper mapper = jackson2ObjectMapperBuilder.build();

		// ObjectMapper为了保障线程安全性，里面的配置类都是一个不可变的对象
		// 所以这里的setDateFormat的内部原理其实是创建了一个新的配置类
		DateFormat dateFormat = mapper.getDateFormat();
		mapper.setDateFormat(new MyDateFormat(dateFormat));
		mapper.setSerializerFactory(mapper.getSerializerFactory().withSerializerModifier(new YlBeanSerializerModifier()));
		mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
		mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, false);
		MappingJackson2HttpMessageConverter mappingJsonpHttpMessageConverter = new MappingJackson2HttpMessageConverter(
				mapper);
		return mappingJsonpHttpMessageConverter;
	}


	/**
	 * Description: 此modifier主要做的事情为：
	 * 当序列化类型为array，list、set时，当值为空时，序列化成[]
	 * 为date,localdate,localdatetime 时，当值为空时，序列化成0
	 * 为数值类型时，当值为空时，序列化成0
	 * 为字符类型时，当值为空时，序列化成“”
	 * @author  feiyang
	 * @date    2019/6/24
	 */
	public class YlBeanSerializerModifier extends BeanSerializerModifier {

		private JsonSerializer<Object> arrayJsonSerializer = new ArrayJsonSerializer();
		private JsonSerializer<Object> strJsonSerializer = new StrJsonSerializer();
		private JsonSerializer<Object> dateJsonSerializer = new DateJsonSerializer();
		private JsonSerializer<Object> numberJsonSerializer = new NumJsonSerializer();

		@Override
		public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
														 List<BeanPropertyWriter> beanProperties) {
			// 循环所有的beanPropertyWriter
			for (BeanPropertyWriter writer : beanProperties) {
				// 判断字段的类型，如果是array，list，set则注册nullSerializer
				if (isArrayType(writer)) {
					//给writer注册一个自己的nullSerializer
					writer.assignNullSerializer(arrayJsonSerializer);
				} else if (isDate(writer)) {
					writer.assignNullSerializer(dateJsonSerializer);
				} else if (isNumber(writer)) {
					writer.assignNullSerializer(numberJsonSerializer);
				} else {
					writer.assignNullSerializer(strJsonSerializer);
				}
			}
			return beanProperties;
		}

		/**
		 * 判断数组类型
		 * @param writer
		 * @return
		 */
		boolean isArrayType(BeanPropertyWriter writer) {
			Class<?> clazz = writer.getType().getRawClass();
			return clazz.isArray() || clazz.equals(List.class) || clazz.equals(Set.class);

		}

		/**
		 * 判断日期类型
		 * @param writer
		 * @return
		 */
		boolean isDate(BeanPropertyWriter writer) {
			Class<?> clazz = writer.getType().getRawClass();
			return clazz.equals(Date.class) || clazz.equals(LocalDateTime.class) || clazz.equals(LocalDate.class);
		}

		/**
		 * 判断数字类型
		 * @param writer
		 * @return
		 */
		boolean isNumber(BeanPropertyWriter writer) {
			Class<?> clazz = writer.getType().getRawClass();
			return clazz.equals(Short.class) || clazz.equals(Integer.class)
					|| clazz.equals(Long.class) || clazz.equals(BigDecimal.class)
					|| clazz.equals(Double.class) || clazz.equals(Float.class);
		}

		/**
		 * 判断字符类型
		 * @param writer
		 * @return
		 */
		boolean isStr(BeanPropertyWriter writer) {
			Class<?> clazz = writer.getType().getRawClass();
			return clazz.equals(String.class) || clazz.equals(Character.class)
					|| clazz.equals(StringBuilder.class) || clazz.equals(StringBuffer.class);
		}
	}

	/**
	 * 数组以及集合序列化实现类
	 */
	public class ArrayJsonSerializer extends JsonSerializer<Object> {

		@Override
		public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
			if (value == null) {
				jgen.writeStartArray();
				jgen.writeEndArray();
			} else {
				jgen.writeObject(value);
			}
		}
	}

	/**
	 * 日期序列化实现类
	 */
	public class DateJsonSerializer extends JsonSerializer<Object> {
		@Override
		public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
			if (value == null) {
				jgen.writeString("");
			} else {
				jgen.writeObject(value);
			}
		}
	}

	/**
	 * 字符串序列化实现类
	 */
	public class StrJsonSerializer extends JsonSerializer<Object> {
		@Override
		public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
			if (value == null) {
				jgen.writeString("");
			} else {
				jgen.writeObject(value);
			}
		}
	}

	/**
	 * 数字序列化实现类
	 */
	public class NumJsonSerializer extends JsonSerializer<Object> {
		@Override
		public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
			if (value == null) {
				jgen.writeNumber(0);
			} else {
				jgen.writeObject(value);
			}
		}
	}

}
